package auth

import (
	"context"
	"fmt"
	"simcard/collector/logger"
	"simcard/config"
	"simcard/errors"
	"simcard/lib/token"
	"simcard/lib/token/jwt"
	"time"
)

const (
	AuthUserKey = "auth_user_key"
	AuthOsKey   = "auth_os_key"
)

type TokenDataKey struct{}

var auth token.Provider

type Options struct {
	UserID uint `json:"user_id"`
}

func Init() func() {
	fmt.Println("auth init...")
	auth = jwt.NewTokenProvider(token.WithPrivateKey(config.Conf.JwtToken.PrivateKey), token.WithPublicKey(config.Conf.JwtToken.PublicKey))
	return func() {}
}

func Generate(options *Options, expire time.Duration) (*token.Token, error) {
	user := &token.UserClaims{
		UserID: options.UserID,
	}

	return auth.Generate(user, token.WithExpiry(expire))
}

func Refresh(tk string) (*token.Token, error) {
	return auth.Refresh(tk)
}

func Verify(tk string) error {
	_, err := auth.Parse(tk)
	if err != nil {
		return err
	}
	return nil
}

func Extract(tk string) (*Options, error) {
	var (
		err  error
		data *token.UserClaims
	)
	if data, err = auth.Parse(tk); err != nil {
		return nil, err
	}

	return &Options{UserID: data.UserID}, nil
}

func ExtractDataFromCtx(ctx context.Context) (*Options, error) {
	var (
		ok   bool
		opts = &Options{}
	)
	value := ctx.Value(TokenDataKey{})
	if opts, ok = value.(*Options); ok {
		return opts, nil
	}
	return nil, errors.New("context does not contain token data")
}

// ContextUserID context获取用户id
func ContextUserID(ctx context.Context) (uint, error) {
	var (
		userId uint
		err    error
	)

	value := ctx.Value(AuthUserKey)
	userId, ok := value.(uint)
	if !ok {
		if value != nil {
			logger.Errorf("context user id type err %T", value)
		}
		return userId, errors.New("token err")
	}
	return userId, err
}
